Skip to content

Fix(WebUi): allow batch resetting provider config to "follow" (iss#6749)#6825

Open
M1LKT wants to merge 4 commits intoAstrBotDevs:masterfrom
M1LKT:fix/#6749
Open

Fix(WebUi): allow batch resetting provider config to "follow" (iss#6749)#6825
M1LKT wants to merge 4 commits intoAstrBotDevs:masterfrom
M1LKT:fix/#6749

Conversation

@M1LKT
Copy link
Contributor

@M1LKT M1LKT commented Mar 23, 2026

Motivation / 改动动机

修复 Issue #6749
在“自定义规则 → 批量操作”场景中,无法通过“跟随配置文件”一次性将多个会话恢复为全局 Provider(聊天模型)。
原因是前端早期用 null 同时表示“未修改”和“跟随配置”,导致界面无法区分“保持不变”和“批量还原为全局”的意图,从而无法实现一键恢复默认配置。

本 PR 的目标是:

  • 在前端使用显式状态表示“跟随配置文件”,并调整批量提交逻辑;
  • 在后端添加/扩展批量删除规则的能力(支持 scope/group_id/rule_key),用于真正删除会话级覆盖配置,从而回退到全局 Provider。

Summary / 改动摘要(前端 + 后端)

  1. 前端(Dashboard)
  • 文件:dashboard/src/views/SessionManagementPage.vue
  • 改动要点:
    • 将 Provider 下拉选项中“跟随配置文件”从原先难以区分的 null 表示,改为显式字符串(示例值:'follow' 或项目内部常量 __astrbot_follow_config__)。
    • 批量操作面板:当用户选择“跟随配置文件”时,前端会发起批量删除规则请求(POST /api/session/batch-delete-rule),并携带 rule_key(例如 provider_perf_chat_completion)以删除对应覆盖;当选择具体 provider 时,仍走 POST /api/session/batch-update-provider
    • 单条规则编辑:编辑器初始化与保存逻辑被调整:若检测到会话无覆盖则显示为 'follow';保存时若选择 'follow' 则触发删除逻辑(调用后端删除单条 rule),否则写入覆盖配置。
    • 按钮/禁用逻辑:canApplyBatch 保持原意——只有在至少选择一项修改且范围满足时才启用,“跟随”作为显式修改项被计入。
  1. 后端(API)
  • 文件:astrbot/dashboard/routes/session_management.py
  • 改动要点:
    • 扩展接口:batch_delete_session_rule 仿照 batch_update_provider,支持接收 umos 列表或 scopeall|group|private|custom_group)和 group_id,并支持 rule_key 参数用于只删除特定规则(例如 provider_perf_chat_completion)。
    • 批量删除与 delete_session_rule (单条删除)逻辑对齐:当传入 rule_key 时仅删除该 key,否则删除该 umo 下全部规则。
    • 保持 batch_update_provider 的语义(用于写入/覆盖 provider),但批量恢复(跟随)不再通过写入特殊值实现,而是参考修改单个会话时的操作,通过删除覆盖规则实现回退。

Screenshots or Test Results / 运行截图或测试结果

PixPin_2026-03-23_10-34-29.mp4

验证步骤(Testing / QA)

  1. 单条规则
  • 在规则编辑器打开某个会话(已存在 provider 覆盖),将聊天模型选择为“跟随配置文件”,保存。验证后端 Preference 表中 provider_perf_chat_completion 对应记录被删除;在界面上该条目显示为“跟随配置文件”。
  1. 批量恢复(范围示例:群组)
  • 打开批量操作,选择范围 group(或 selected 并选择多项),将聊天模型选择为“跟随配置文件”,应用。
  • 验证:后端相应会话的 provider_perf_chat_completion 覆盖记录被删除;会话实际使用全局 provider(可以通过触发一次对话并观察 provider 选择或日志来确认)。
  1. 保持为空不修改
  • 在批量面板对某项保持空(不选择),提交后验证该字段未改变。
  1. 回归测试
  • 验证 batch_update_provider 在选择具体 provider_id 时仍旧能正确写入覆盖。

受影响文件列表

  • Dashboard (前端)

    • dashboard/src/views/SessionManagementPage.vue — Provider 选项、批量提交逻辑、规则编辑器初始化保存逻辑
  • Backend (API)

    • astrbot/dashboard/routes/session_management.py — 扩展 batch_delete_session_rule,并保证 delete_session_rule 与之行为一致

(变更均为本次 PR 的核心改动;其他关联小改动以代码 diff 为准)

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”
  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。
  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

@auto-assign auto-assign bot requested review from Fridemn and advent259141 March 23, 2026 02:50
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. labels Mar 23, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The magic string 'astrbot_follow_config' is repeated in multiple places on the frontend; consider extracting it into a shared constant to avoid typos and make future changes easier.
  • You added batchTtsProviderOptions but the batch TTS select still appears to use the original ttsProviderOptions; please confirm the correct options source is wired up or remove the unused computed to avoid confusion.
  • Enabling config.use_reloader = True in server.py affects runtime behavior and may not be desirable in non‑development environments; consider making this conditional on an environment flag or local dev setting.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The magic string '__astrbot_follow_config__' is repeated in multiple places on the frontend; consider extracting it into a shared constant to avoid typos and make future changes easier.
- You added `batchTtsProviderOptions` but the batch TTS select still appears to use the original `ttsProviderOptions`; please confirm the correct options source is wired up or remove the unused computed to avoid confusion.
- Enabling `config.use_reloader = True` in `server.py` affects runtime behavior and may not be desirable in non‑development environments; consider making this conditional on an environment flag or local dev setting.

## Individual Comments

### Comment 1
<location path="dashboard/src/views/SessionManagementPage.vue" line_range="674" />
<code_context>
     chatProviderOptions() {
       return [
-        { label: this.tm('provider.followConfig'), value: null },
+        { label: this.tm('provider.followConfig'), value: '__astrbot_follow_config__' },
         ...this.availableChatProviders.map(p => ({
           label: `${p.name} (${p.model})`,
</code_context>
<issue_to_address>
**suggestion:** Extract the follow-config sentinel string into a shared constant to avoid duplication and typo risk.

The `'__astrbot_follow_config__'` literal appears in several places (defaults, options, checks). Please define a single shared constant (e.g. `const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'` or a `data`/`computed` property) and reference it everywhere to avoid typos and simplify future changes.

Suggested implementation:

```
const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'

        chat_completion: FOLLOW_CONFIG_SENTINEL,
        speech_to_text: FOLLOW_CONFIG_SENTINEL,
        text_to_speech: FOLLOW_CONFIG_SENTINEL,
      },

      // 插件配置

    chatProviderOptions() {
      return [
        { label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
        ...this.availableChatProviders.map(p => ({
          label: `${p.name} (${p.model})`,
          value: p.id

    sttProviderOptions() {
      return [
        { label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
        ...this.availableSttProviders.map(p => ({
          label: `${p.name} (${p.model})`,
          value: p.id

```

1. Place the `const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'` declaration at the top of the `<script>` block (or just after existing imports) to match your project's conventions; the SEARCH/REPLACE block above assumes this snippet is near the top of the script, but you may need to move the constant accordingly.
2. Search the remainder of `SessionManagementPage.vue` for any other occurrences of `'__astrbot_follow_config__'` (e.g. in watchers, computed properties, validation logic) and replace them with `FOLLOW_CONFIG_SENTINEL` as well.
3. If this sentinel is used in other files (e.g. shared stores or components), consider moving `FOLLOW_CONFIG_SENTINEL` into a shared constants module (e.g. `src/constants/providers.ts`) and importing it here and elsewhere to fully centralize the value.
</issue_to_address>

### Comment 2
<location path="astrbot/dashboard/routes/session_management.py" line_range="384-385" />
<code_context>
             if not isinstance(umos, list):
                 return Response().error("参数 umos 必须是数组").__dict__

+            if rule_key and rule_key not in AVAILABLE_SESSION_RULE_KEYS:
+                return Response().error(f"不支持的规则键: {rule_key}").__dict__
+
             # 批量删除
</code_context>
<issue_to_address>
**suggestion:** Consider validating `scope` values explicitly to produce clearer errors for invalid input.

An unsupported `scope` (e.g. a typo) currently just leaves `umos` empty and triggers the generic "缺少必要参数: umos 或有效的 scope" error, which hides that `scope` itself was invalid. Please validate `scope` against the allowed set and return a specific error (e.g. "不支持的 scope 值") before expanding it into `umos` so invalid scopes aren’t treated the same as missing `umos`.

Suggested implementation:

```python
                    elif scope == "all":
                        umos = all_umos

            # 显式校验 scope,避免无效 scope 静默失败
            allowed_scopes = {"all"}
            if scope and scope not in allowed_scopes:
                return Response().error("不支持的 scope 值").__dict__

            if not umos:
                return Response().error("缺少必要参数: umos 或有效的 scope").__dict__

```

To fully align this change with the rest of the function:

1. Update `allowed_scopes` to include all currently支持的 scope 值(例如如果上文有 `if scope == "online"`, `if scope == "selected"` 等分支,请将这些字符串也加入到 `allowed_scopes` 集合中),确保不会误报合法 scope 为无效。
2. If there is a centralized definition of allowed scopes elsewhere in the codebase (e.g. a constant like `AVAILABLE_SESSION_SCOPES`), replace the hardcoded `allowed_scopes` set with that constant to keep things DRY and consistent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

chatProviderOptions() {
return [
{ label: this.tm('provider.followConfig'), value: null },
{ label: this.tm('provider.followConfig'), value: '__astrbot_follow_config__' },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Extract the follow-config sentinel string into a shared constant to avoid duplication and typo risk.

The '__astrbot_follow_config__' literal appears in several places (defaults, options, checks). Please define a single shared constant (e.g. const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__' or a data/computed property) and reference it everywhere to avoid typos and simplify future changes.

Suggested implementation:

const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__'

        chat_completion: FOLLOW_CONFIG_SENTINEL,
        speech_to_text: FOLLOW_CONFIG_SENTINEL,
        text_to_speech: FOLLOW_CONFIG_SENTINEL,
      },

      // 插件配置

    chatProviderOptions() {
      return [
        { label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
        ...this.availableChatProviders.map(p => ({
          label: `${p.name} (${p.model})`,
          value: p.id

    sttProviderOptions() {
      return [
        { label: this.tm('provider.followConfig'), value: FOLLOW_CONFIG_SENTINEL },
        ...this.availableSttProviders.map(p => ({
          label: `${p.name} (${p.model})`,
          value: p.id

  1. Place the const FOLLOW_CONFIG_SENTINEL = '__astrbot_follow_config__' declaration at the top of the <script> block (or just after existing imports) to match your project's conventions; the SEARCH/REPLACE block above assumes this snippet is near the top of the script, but you may need to move the constant accordingly.
  2. Search the remainder of SessionManagementPage.vue for any other occurrences of '__astrbot_follow_config__' (e.g. in watchers, computed properties, validation logic) and replace them with FOLLOW_CONFIG_SENTINEL as well.
  3. If this sentinel is used in other files (e.g. shared stores or components), consider moving FOLLOW_CONFIG_SENTINEL into a shared constants module (e.g. src/constants/providers.ts) and importing it here and elsewhere to fully centralize the value.

Comment on lines +384 to +385
if rule_key and rule_key not in AVAILABLE_SESSION_RULE_KEYS:
return Response().error(f"不支持的规则键: {rule_key}").__dict__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider validating scope values explicitly to produce clearer errors for invalid input.

An unsupported scope (e.g. a typo) currently just leaves umos empty and triggers the generic "缺少必要参数: umos 或有效的 scope" error, which hides that scope itself was invalid. Please validate scope against the allowed set and return a specific error (e.g. "不支持的 scope 值") before expanding it into umos so invalid scopes aren’t treated the same as missing umos.

Suggested implementation:

                    elif scope == "all":
                        umos = all_umos

            # 显式校验 scope,避免无效 scope 静默失败
            allowed_scopes = {"all"}
            if scope and scope not in allowed_scopes:
                return Response().error("不支持的 scope 值").__dict__

            if not umos:
                return Response().error("缺少必要参数: umos 或有效的 scope").__dict__

To fully align this change with the rest of the function:

  1. Update allowed_scopes to include all currently支持的 scope 值(例如如果上文有 if scope == "online", if scope == "selected" 等分支,请将这些字符串也加入到 allowed_scopes 集合中),确保不会误报合法 scope 为无效。
  2. If there is a centralized definition of allowed scopes elsewhere in the codebase (e.g. a constant like AVAILABLE_SESSION_SCOPES), replace the hardcoded allowed_scopes set with that constant to keep things DRY and consistent.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses issue #6749, which prevented users from resetting multiple sessions to the global Provider configuration in the "Custom Rules → Batch Operations" scenario. The frontend now uses an explicit state to represent "Follow Configuration," and the backend has been enhanced with the ability to batch delete rules, enabling a true reversion to the global Provider.

Highlights

  • 前端改动: 将 Provider 下拉选项中“跟随配置文件”从原先难以区分的 null 表示,改为显式字符串('follow' 或项目内部常量 __astrbot_follow_config__),并调整批量提交逻辑。
  • 后端改动: 扩展了 batch_delete_session_rule 接口,支持接收 umos 列表或 scopeall|group|private|custom_group)和 group_id,并支持 rule_key 参数用于只删除特定规则。
  • 批量操作: 当用户选择“跟随配置文件”时,前端会发起批量删除规则请求(POST /api/session/batch-delete-rule),并携带 rule_key(例如 provider_perf_chat_completion)以删除对应覆盖;当选择具体 provider 时,仍走 POST /api/session/batch-update-provider
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次拉取请求修复了批量重置提供商配置为“跟随配置文件”的问题,通过在前端使用显式字符串 __astrbot_follow_config__ 代替 null 来表示“跟随配置文件”状态,并相应地调整了批量操作的逻辑。后端扩展了 batch_delete_session_rule 接口,使其能够根据 scoperule_key 批量删除会话规则,从而实现回退到全局配置。这些改动提高了配置管理的清晰度和灵活性。但在后端代码中发现一个关键的 NameError,以及一些可以改进的地方。

I am having trouble creating individual review comments. Click here to see my feedback.

astrbot/dashboard/routes/session_management.py (385)

critical

变量 AVAILABLE_SESSION_RULE_KEYS 在此文件中未定义。这会导致 NameError,从而使 API 端点无法正常工作。请确保在使用前导入或定义此变量。

astrbot/dashboard/routes/session_management.py (364-374)

medium

当前通过 user_id 字符串中是否包含 ':group:'':private:' 来判断会话类型,这种方式依赖于 user_id 的特定格式。如果 user_id 的生成规则发生变化,这部分逻辑可能会失效。建议考虑是否有更健壮的方式来识别会话类型,例如在 ConversationV2PlatformSession 模型中增加一个明确的 is_groupchat_type 字段。

astrbot/dashboard/server.py (374)

medium

config.use_reloader 设置为 True 对于开发环境非常有用,因为它可以在代码更改时自动重新加载服务器。然而,在生产环境中,这通常会导致性能开销和潜在的稳定性问题。建议根据环境(例如通过环境变量)来动态设置此值,在生产环境中将其设置为 False

dashboard/src/views/SessionManagementPage.vue (691-717)

medium

你为 chatProviderOptionsttsProviderOptions 创建了 batchChatProviderOptionsbatchTtsProviderOptions。然而,sttProviderOptions 并没有对应的 batchSttProviderOptions。如果 STT 提供商也需要进行批量操作,那么也应该为其创建一个 batchSttProviderOptions 以保持一致性,并确保所有批量操作功能完整。

@M1LKT M1LKT changed the title Fix(#6749): allow batch resetting provider config to "follow Fix(WebUi): allow batch resetting provider config to "follow" (iss#6749) Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant